home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / Libraries / ApplicationPreferencesLib / ApplicationPreferencesLib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-16  |  15.7 KB  |  549 lines  |  [TEXT/KAHL]

  1. /* Functions for displaying, changing, reading, and saving application
  2.     preferences.
  3.     
  4.     94/01/12 aih - overrides popup controls' mouse down handler
  5.     93/12/23 aih - created */
  6.  
  7. #include <Packages.h>
  8. #include <Script.h>
  9. #include "pstr.h"
  10. #include "ApplicationPreferencesLib.h"
  11. #include "ArchiveLib.h"
  12. #include "DialogLib.h"
  13. #include "FontLib.h"
  14. #include "MemoryLib.h"
  15. #include "MenuLib.h"
  16. #include "PopupLib.h"
  17. #include "PreferencesLib.h"
  18. #include "ResourceConstantsLib.h"
  19. #include "ResourceLib.h"
  20. #include "ResourceTypeLib.h"
  21. #include "TextWrapDialogLib.h"
  22.  
  23. /* version of preferences data */
  24. #define APP_PREFS_VERSION (1)
  25.  
  26. /* items in preferences dialog */
  27. enum {
  28.  
  29.     iTextFrame = 1,
  30.     iTextTitle,
  31.  
  32.     iStyleFrame,
  33.     iStyleTitle,
  34.     iStyledButton,
  35.     iUnstyledButton,
  36.     iExtendedButton,
  37.  
  38.     iWrapFrame,
  39.     iWrapTitle,
  40.     iWrapButton,
  41.     iWrapDontButton,
  42.     iWrapMarginText,
  43.     iWrapUnitsText,
  44.     
  45.     iFontPopup,
  46.     iSizeTitle,
  47.     iSizeText,
  48.     iSizePopup,
  49.     iJustPopup,
  50.     
  51.     iUnitsPopup,
  52.  
  53.     iDefaultsButton,
  54.     
  55.     /* items that are used to identify objects */
  56.     iWrapRadioGroup = iWrapFrame,
  57.     iStyleRadioGroup = iStyleFrame,
  58.     
  59.     iLast
  60. };
  61.  
  62. /* conversion factors from units to pixels */
  63. #define MAX_UNITS (RLS_UNITS_LAST - 1)
  64. #define CENT_PER_INCH    (2.54)
  65. #define PIXELS_PER_INCH    (72.0)    /* IM-VI, p12-7 */
  66. #define POINTS_PER_INCH    (72.27)    /* IM-VI, p12-7 */
  67. static float gUnitConversions[MAX_UNITS] = {
  68.     PIXELS_PER_INCH / CENT_PER_INCH / 10,        /* pixels per millimeter */
  69.     PIXELS_PER_INCH / CENT_PER_INCH,                /* pixels per centimeter */
  70.     PIXELS_PER_INCH,                                    /* pixels per inch */
  71.     PIXELS_PER_INCH / POINTS_PER_INCH,            /* pixels per point */
  72. };
  73.  
  74. static AppPrefsWindowHandle gAppPrefsWindow;
  75.  
  76. /* return a handle to the popup control's menu */
  77. static MenuHandle CtlPopupMenu(ControlHandle ctl)
  78. {
  79.     require(CtlValid(ctl));
  80.     return((**(PopupPrivateHandle) (**ctl).contrlData).mHandle);
  81. }
  82.  
  83. /* return the menu of a popup control in the dialog */
  84. static MenuHandle DlgPopupMenu(DialogPtr dlg, short item)
  85. {
  86.     return(CtlPopupMenu(DlgCtl(dlg, item)));
  87. }
  88.  
  89. /* return default values for preferences */
  90. const AppPrefsType *AppPrefsDefaults(void)
  91. {
  92.     static AppPrefsType defaults;
  93.     static Boolean initialized;
  94.     
  95.     if (! initialized) {
  96.         /* word wrap is enabled if text is right justified since TextEdit
  97.             doesn't display the text correctly if it's right justified and
  98.             word wrap is disabled */
  99.         defaults.text.kind = TX_STYLED_KIND;
  100.         defaults.text.state.font = GetAppFont();
  101.         defaults.text.state.size = GetDefFontSize();
  102.         defaults.text.state.mode = srcOr;
  103.         defaults.text.state.face = 0;
  104.         defaults.text.wrap = true;
  105.         defaults.text.buffer = false;
  106.         defaults.text.margin = 6 * PIXELS_PER_INCH;
  107.         defaults.text.just = GetSysJust();
  108.         defaults.units.id = (IUMetric() ? RLS_UNITS_CENTIMETERS : RLS_UNITS_INCHES);
  109.         check(1 <= defaults.units.id && defaults.units.id <= MAX_UNITS);
  110.         defaults.units.conversion = gUnitConversions[defaults.units.id - 1];
  111.         ResStrLen(RLS_UNITS_SINGULAR, defaults.units.id, defaults.units.singular, sizeof(CStr31));
  112.         ResStrLen(RLS_UNITS_PLURAL, defaults.units.id, defaults.units.plural, sizeof(CStr31));
  113.         initialized = true;
  114.     }
  115.     return(&defaults);
  116. }
  117.  
  118. /* return application's global preferences structure */
  119. AppPrefsType *AppPrefs(void)
  120. {
  121.     static AppPrefsType prefs;
  122.     static Boolean initialized;
  123.     
  124.     if (! initialized) {
  125.         prefs = *AppPrefsDefaults();
  126.         initialized = true;
  127.     }
  128.     return(&prefs);
  129. }
  130.  
  131. /* adjust size popup menu--set value, outline sizes, add/remove user's choice */
  132. static AdjustSizeMenu(AppPrefsWindowHandle prefs)
  133. {
  134.     AppPrefsType *settings = (**prefs).appPrefs;
  135.     ControlHandle ctl;
  136.     MenuHandle menu;
  137.     Str255 pstr;
  138.     CStr255 str;
  139.     short item;
  140.     
  141.     /* adjust user's choice */
  142.     NumToString(settings->text.state.size, pstr);
  143.     ctl = DlgCtl((**prefs).dlg, iSizePopup);
  144.     menu = DlgPopupMenu((**prefs).dlg, iSizePopup);
  145.     item = MenuFindItem(menu, p2cstrcpy(str, pstr));
  146.     if (item == 0) {
  147.  
  148.         /* used entered a size not found in the menu, so add the
  149.             user's choice as the first item in the menu (IM-VI, p2-37) */
  150.         if (! (**prefs).sizeHasUserChoice) {
  151.             short nitems;
  152.             InsMenuItem(menu, (StringPtr) "\p(-", 0);
  153.             InsMenuItem(menu, pstr, 0);
  154.             for (nitems = CountMItems(menu); nitems > 0; nitems--)
  155.                 SetItemMark(menu, nitems, noMark);
  156.             SetItemMark(menu, 1, checkMark);
  157.             SetCtlMax(ctl, GetCtlMax(ctl) + 2);
  158.             (**prefs).sizeHasUserChoice = true;
  159.         }
  160.         SetItem(menu, 1, pstr);
  161.         SetCtlValue(ctl, 1);
  162.     }
  163.     else if (item > 2 && (**prefs).sizeHasUserChoice) {
  164.  
  165.         /* remove user's choice, since selected item is in menu */
  166.         (**prefs).sizeHasUserChoice = false;
  167.         SetCtlValue(ctl, 1);
  168.         DelMenuItem(menu, 1);
  169.         DelMenuItem(menu, 1);
  170.         SetCtlMax(ctl, GetCtlMax(ctl) - 2);
  171.         SetCtlValue(ctl, item - 2);
  172.     }
  173.     else
  174.         SetCtlValue(ctl, item);
  175.  
  176.     /* adjust size menu */
  177.     MenuOutlineSizes(DlgPopupMenu((**prefs).dlg, iSizePopup),
  178.         FontID(settings->text.state.font), true);
  179. }
  180.  
  181. static void SetupDialog(AppPrefsWindowHandle prefs)
  182. {
  183.     AppPrefsType *settings = (**prefs).appPrefs;
  184.     ControlHandle ctl;
  185.     MenuHandle menu;
  186.     Str255 pstr;
  187.     CStr255 str;
  188.     short item;
  189.     
  190.     /* set text kind radio buttons */
  191.     switch (settings->text.kind) {
  192.     case TX_STYLED_KIND:
  193.         RadioClickID((**prefs).text.kindRadio, iStyledButton);
  194.         break;
  195.     case TX_UNSTYLED_KIND:
  196.         RadioClickID((**prefs).text.kindRadio, iUnstyledButton);
  197.         break;
  198.     case TX_EXTENDED_KIND:
  199.         RadioClickID((**prefs).text.kindRadio, iExtendedButton);
  200.         break;
  201.     }
  202.     
  203.     /* set text word wrap */
  204.     TxWrapDialogValuesSet((**prefs).dlg, (**prefs).text.wrapRadio,
  205.         iWrapButton, iWrapDontButton, iWrapMarginText, iWrapUnitsText,
  206.         settings->text.wrap, settings->text.margin);
  207.  
  208.     /* set value of font popup menu */
  209.     GetFontName(FontID(settings->text.state.font), pstr);
  210.     menu = DlgPopupMenu((**prefs).dlg, iFontPopup);
  211.     item = MenuFindItem(menu, p2cstrcpy(str, pstr));
  212.     DlgCtlValueSet((**prefs).dlg, iFontPopup, item);
  213.  
  214.     /* adjust font size type-in menu and text */
  215.     AdjustSizeMenu(prefs);
  216.     DlgNumSet((**prefs).dlg, iSizeText, settings->text.state.size);    
  217.     
  218.     /* set value of units popup menu */
  219.     check(1 <= settings->units.id && settings->units.id <= MAX_UNITS);
  220.     DlgCtlValueSet((**prefs).dlg, iUnitsPopup, settings->units.id);
  221.  
  222.     /* set value of justification popup menu */
  223.     switch (settings->text.just) {
  224.     case teJustRight:        item = 3; break;
  225.     case teJustCenter:    item = 2; break;
  226.     case teForceLeft:        item = 1; break;
  227.     case teJustLeft:        item = 1; break;
  228.     default:                    item = 1; break;
  229.     }
  230.     DlgCtlValueSet((**prefs).dlg, iJustPopup, item);
  231. }
  232.  
  233. /* Handler which overrides the mouse down handler for the popup menu controls,
  234.     allowing us to adjust the popup menus before they're selected. */
  235. static Boolean OverrideCtlMousedown(EventObjectType object, EventRecord *event)
  236. {
  237.     ControlHandle ctl = object;
  238.     DialogPtr dlg = CtlWindow(ctl);
  239.     AppPrefsWindowHandle prefs = WinData(dlg);
  240.     
  241.     MenuEnable(CtlPopupMenu(ctl), 0, true);
  242.     if (ctl == WinRegisteredID(dlg, iSizePopup)) {
  243.         AdjustSizeMenu(prefs);
  244.         DlgTextSelectAll(dlg, iSizeText);
  245.     }
  246.     return(CtlMouseDown(ctl, event));
  247. }
  248.  
  249. /* create window to display and set preferences */
  250. AppPrefsWindowHandle AppPrefsBegin(AppPrefsType *appPrefs)
  251. {
  252.     volatile AppPrefsWindowHandle prefs = NULL;
  253.     DialogPtr dlg = NULL;        /* the dialog displaying the prefs */
  254.     RadioHandle radio = NULL;    /* for setting up radio button groups */
  255.     MenuHandle menu = NULL;        /* for setting up popup menus */
  256.     Rect frame, title;            /* frame and title rectangles for radio buttons */
  257.     static EventTableType overrideTable; /* for overriding event handler */
  258.     short i;
  259.     
  260.     TRY {
  261.         prefs = HandleBeginClear(sizeof(AppPrefsWindowType));
  262.         (**prefs).appPrefs = appPrefs;
  263.         dlg = DlgBegin(RLD_PREFERENCES);
  264.         (**prefs).dlg = dlg;
  265.         
  266.         /* create text group frame; we use a radio button structure since
  267.             it already handles display of a frame with a title, though no
  268.             radio buttons are actually installed into it */
  269.         DlgBox(dlg, iTextFrame, &frame);
  270.         DlgBox(dlg, iTextTitle, &title);
  271.         radio = RadioBegin(dlg, &frame, &title);
  272.         (**prefs).text.frameRadio = radio;
  273.         
  274.         /* create text kind radio buttons */
  275.         DlgBox(dlg, iStyleFrame, &frame);
  276.         DlgBox(dlg, iStyleTitle, &title);
  277.         radio = RadioBegin(dlg, &frame, &title);
  278.         (**prefs).text.kindRadio = radio;
  279.         RadioAdd(radio, DlgCtl(dlg, iStyledButton), iStyledButton);
  280.         RadioAdd(radio, DlgCtl(dlg, iUnstyledButton), iUnstyledButton);
  281.         RadioAdd(radio, DlgCtl(dlg, iExtendedButton), iExtendedButton);
  282.         WinRegisterID(dlg, radio, iStyleRadioGroup);
  283.  
  284.         /* setup wrap margin items */
  285.         radio = TxWrapDialogSetup(dlg, iWrapButton, iWrapDontButton,
  286.                         iWrapMarginText, iWrapUnitsText, iWrapFrame, iWrapTitle,
  287.                         (**prefs).appPrefs->text.wrap,
  288.                         (**prefs).appPrefs->text.margin);
  289.         (**prefs).text.wrapRadio = radio;
  290.         WinRegisterID(dlg, radio, iWrapRadioGroup);
  291.         
  292.         /* setup units popup menu */
  293.         menu = DlgPopupMenu(dlg, iUnitsPopup);
  294.         check(MenuValid(menu));
  295.         if (CountMItems(menu) == 0) {
  296.             for (i = 1; i < RLS_UNITS_LAST; i++) {
  297.                 CStr31 name;
  298.                 ResStrLen(RLS_UNITS_PLURAL, i, name, sizeof(CStr31));
  299.                 AppendMenu(menu, c2pstr(name));
  300.             }
  301.             DlgCtlMaxSet(dlg, iUnitsPopup, CountMItems(menu));
  302.         }
  303.         
  304.         /* override mouse down handlers for popup menus */
  305.         overrideTable = *(const EventTableType *) CtlEventTable();
  306.         overrideTable.focusWindow.mousedown = OverrideCtlMousedown;
  307.         WinObjectTableSet(dlg, DlgCtl(dlg, iSizePopup), &overrideTable);
  308.         WinObjectTableSet(dlg, DlgCtl(dlg, iFontPopup), &overrideTable);
  309.         WinObjectTableSet(dlg, DlgCtl(dlg, iJustPopup), &overrideTable);
  310.         WinObjectTableSet(dlg, DlgCtl(dlg, iUnitsPopup), &overrideTable);
  311.         check(WinData(dlg) == NULL);
  312.         WinDataSet(dlg, prefs);
  313.  
  314.         /* set font size text field to be an integer field */
  315.         TxHookKeySet(WinRegisteredID(dlg, iSizeText), TxHookKeyUnsignedInteger);
  316.         
  317.         /* finish setting up window */
  318.         SetupDialog(prefs);
  319.         DlgTextSelectAll((**prefs).dlg, iWrapMarginText);
  320.         WinRegister(dlg, prefs, AppPrefsEventTable());
  321.         WinZoomRestore(dlg, PrefsFile(), PREFS_APPLICATION_POSITION);
  322.         WinShow(dlg);
  323.     } CATCH {
  324.         AppPrefsEnd(prefs);
  325.     } ENDTRY;
  326.     return(prefs);
  327. }
  328.  
  329. /* dispose of the preferences window */
  330. void AppPrefsEnd(AppPrefsWindowHandle prefs)
  331. {
  332.     if (prefs) {
  333.         if ((**prefs).dlg)
  334.             WinZoomSave((**prefs).dlg, PrefsFile(), PREFS_APPLICATION_POSITION);
  335.         WinUnregister((**prefs).dlg, prefs);
  336.         RadioEnd((**prefs).text.frameRadio);
  337.         RadioEnd((**prefs).text.kindRadio);
  338.         RadioEnd((**prefs).text.wrapRadio);
  339.         DlgEnd((**prefs).dlg);
  340.         HandleEnd(prefs);
  341.     }
  342. }
  343.  
  344. /* handle a click in the preferences window */
  345. void AppPrefsClicked(AppPrefsWindowHandle prefs, long clickedID)
  346. {
  347.     Boolean wrap;        /* for getting word wrap */
  348.     float margin;        /* for getting wrap margin */
  349.     short font;            /* for getting font */
  350.     long size;            /* for getting font size */
  351.     Str255 item;        /* for getting menu items */
  352.     
  353.     switch (clickedID) {
  354.     case iStyleRadioGroup:
  355.         switch (RadioSelectedID((**prefs).text.kindRadio)) {
  356.         case iStyledButton:    (**prefs).appPrefs->text.kind = TX_STYLED_KIND; break;
  357.         case iUnstyledButton:(**prefs).appPrefs->text.kind = TX_UNSTYLED_KIND; break;
  358.         case iExtendedButton:(**prefs).appPrefs->text.kind = TX_EXTENDED_KIND; break;
  359.         }
  360.         SetupDialog(prefs);
  361.         break;
  362.     case iWrapMarginText:
  363.         RadioClickID((**prefs).text.wrapRadio, iWrapButton);
  364.         /* no break */
  365.     case iWrapRadioGroup:
  366.         TxWrapDialogValues((**prefs).dlg, (**prefs).text.wrapRadio,
  367.             iWrapButton, iWrapDontButton, iWrapMarginText, &wrap, &margin);
  368.         (**prefs).appPrefs->text.wrap = wrap;
  369.         (**prefs).appPrefs->text.margin = margin;
  370.         if (clickedID != iWrapMarginText)
  371.             SetupDialog(prefs); /* don't call for text field */
  372.         break;
  373.     case iFontPopup:
  374.         GetItem(DlgPopupMenu((**prefs).dlg, iFontPopup),
  375.                   DlgCtlValue((**prefs).dlg, iFontPopup), item);
  376.         GetFNum(item, &font);
  377.         (**prefs).appPrefs->text.state.font = font;
  378.         SetupDialog(prefs);
  379.         break;
  380.     case iSizeText:
  381.         size = DlgNum((**prefs).dlg, iSizeText);
  382.         if (size < TX_MIN_FONT)
  383.             size = TX_MIN_FONT;
  384.         else if (size > TX_MAX_FONT)
  385.             size = TX_MAX_FONT;
  386.         (**prefs).appPrefs->text.state.size = size;
  387.         /* don't call SetupDialog for open text field, or it will overwrite
  388.             whatever the user is typing */
  389.         break;
  390.     case iSizePopup:
  391.         GetItem(DlgPopupMenu((**prefs).dlg, iSizePopup),
  392.                   DlgCtlValue((**prefs).dlg, iSizePopup), item);
  393.         StringToNum(item, &size);
  394.         if (size < TX_MIN_FONT)
  395.             size = TX_MIN_FONT;
  396.         else if (size > TX_MAX_FONT)
  397.             size = TX_MAX_FONT;
  398.         (**prefs).appPrefs->text.state.size = size;
  399.         SetupDialog(prefs);
  400.         break;
  401.     case iJustPopup:
  402.         switch (DlgCtlValue((**prefs).dlg, iJustPopup)) {
  403.         case 1: (**prefs).appPrefs->text.just = teForceLeft; break;
  404.         case 2: (**prefs).appPrefs->text.just = teJustCenter; break;
  405.         case 3: (**prefs).appPrefs->text.just = teJustRight; break;
  406.         }
  407.         SetupDialog(prefs);
  408.         break;
  409.     case iUnitsPopup:
  410.         (**prefs).appPrefs->units.id = DlgCtlValue((**prefs).dlg, iUnitsPopup);
  411.         (**prefs).appPrefs->units.conversion = gUnitConversions[(**prefs).appPrefs->units.id - 1];
  412.         check(1 <= (**prefs).appPrefs->units.id && (**prefs).appPrefs->units.id <= MAX_UNITS);
  413.         ResStrLen(RLS_UNITS_SINGULAR, (**prefs).appPrefs->units.id, (**prefs).appPrefs->units.singular, sizeof(CStr31));
  414.         ResStrLen(RLS_UNITS_PLURAL, (**prefs).appPrefs->units.id, (**prefs).appPrefs->units.plural, sizeof(CStr31));
  415.         SetupDialog(prefs);
  416.         break;
  417.     case iDefaultsButton:
  418.         *(**prefs).appPrefs = *AppPrefsDefaults();
  419.         SetupDialog(prefs);
  420.         DlgTextSelectAll((**prefs).dlg, iWrapMarginText);
  421.         break;
  422.     default:
  423.         SetupDialog(prefs);
  424.         break;
  425.     }
  426. }
  427.  
  428. /* create and/or select the preferences window */
  429. void AppPrefsShow(void)
  430. {
  431.     if (! gAppPrefsWindow)
  432.         gAppPrefsWindow = AppPrefsBegin(AppPrefs());
  433.     WinSelect((**gAppPrefsWindow).dlg);
  434. }
  435.  
  436. /* hide the preferences window */
  437. void AppPrefsHide(void)
  438. {
  439.     if (gAppPrefsWindow) {
  440.         AppPrefsWrite((**gAppPrefsWindow).appPrefs);
  441.         AppPrefsEnd(gAppPrefsWindow);
  442.         gAppPrefsWindow = NULL;
  443.     }
  444. }
  445.  
  446. /* read the preferences data from the preferences file */
  447. void AppPrefsRead(AppPrefsType *prefs)
  448. {
  449.     size_t size;
  450.     long version;
  451.     volatile Boolean failed = false;
  452.  
  453.     TRY {
  454.         *prefs = *AppPrefsDefaults();
  455.         if (! failed) {
  456.             FailInfoSet(RLS_ERR_READ, FileName(PrefsFile()), NULL);
  457.             PrefsOpen();
  458.             if (ResExists1(RES_PREF_TYPE, PREFS_APPLICATION)) {
  459.                 version = APP_PREFS_VERSION;
  460.                 size = sizeof(AppPrefsType);
  461.                 ArchiveReadRes(RES_PREF_TYPE, PREFS_APPLICATION, prefs, &size, &version);
  462.                 if (size != sizeof(AppPrefsType) || version != APP_PREFS_VERSION)
  463.                     *prefs = *AppPrefsDefaults();
  464.             }
  465.             PrefsClose();
  466.             FailInfoClear();
  467.         }
  468.     } CATCH {
  469.         if (! failed) {
  470.             failed = true;
  471.             PrefsClose();
  472.             FailDisplay();
  473.             FailClear();
  474.             RETRY;
  475.         }
  476.     } ENDTRY;
  477. }
  478.  
  479. /* write the preferences data to the preferences file */
  480. void AppPrefsWrite(const AppPrefsType *prefs)
  481. {
  482.     volatile Boolean opened = false;
  483.     volatile Boolean failed = false;
  484.     
  485.     TRY {
  486.         if (! failed) {
  487.             FailInfoSet(RLS_ERR_WRITE, FileName(PrefsFile()), NULL);
  488.             if (! PrefsReferenceNumber()) {
  489.                 PrefsOpen();
  490.                 opened = true;
  491.             }
  492.             ArchiveWriteRes(RES_PREF_TYPE, PREFS_APPLICATION, prefs,
  493.                 sizeof(AppPrefsType), APP_PREFS_VERSION);
  494.             if (opened)
  495.                 PrefsClose();
  496.             FailInfoClear();
  497.         }
  498.     } CATCH {
  499.         if (! failed) {
  500.             failed = true;
  501.             if (opened)
  502.                 PrefsClose();
  503.             FailDisplay();
  504.             FailClear();
  505.             RETRY;
  506.         }
  507.     } ENDTRY;
  508. }
  509.  
  510. /* handle a preferences related menu command */
  511. Boolean AppPrefsMenu(const MenuPickType *pick)
  512. {
  513.     Boolean handled = false;
  514.     
  515.     switch (pick->cmd) {
  516.     case CMD_PREFERENCES:
  517.         AppPrefsShow();
  518.         handled = true;
  519.         break;
  520.     case CMD_CLOSE:
  521.         if (gAppPrefsWindow && FocusWindow() == (**gAppPrefsWindow).dlg) {
  522.             AppPrefsHide();
  523.             handled = true;
  524.         }
  525.         break;
  526.     }
  527.     return(handled);
  528. }
  529.  
  530. /* adjust preferences related menu items */
  531. void AppPrefsAdjustMenu(void)
  532. {
  533.     if (gAppPrefsWindow && FocusWindow() == (**gAppPrefsWindow).dlg) {
  534.         MenuCmdEnable(CMD_CLOSE);
  535.         MenuCmdCheck(CMD_PREFERENCES, true);
  536.     }
  537.     if (! WinModalHasFocus() && MemWarning() < MEM_WARNING_VERY_LOW) {
  538.         MenuCmdEnable(CMD_PREFERENCES);
  539.         MenuCmdEnable(CMD_EDIT);
  540.     }
  541. }
  542.  
  543. /* close preferences window if memory is low */
  544. void AppPrefsMemoryLow(void)
  545. {
  546.     if (MemWarning() >= MEM_WARNING_VERY_LOW)
  547.         AppPrefsHide();
  548. }
  549.